package mq

import (
	"e-commerce/services/order-service/internal/repository"
	"encoding/json"
	"fmt"
	"log"
	"os"

	"github.com/streadway/amqp"
	yaml "sigs.k8s.io/yaml/goyaml.v3"
)

type OrderMQ struct {
	conn    *amqp.Connection
	channel *amqp.Channel
}

type mqconfig struct {
	Mq MqConfig `yaml:"rabbitmq"`
}

type MqConfig struct {
	Host     string `yaml:"host"`
	Port     string `yaml:"port"`
	User     string `yaml:"user"`
	Password string `yaml:"password"`
	Vhost    string `yaml:"vhost"`
}

func NewOrderMQ(configPath string) *OrderMQ {
	yamlFile, err := os.ReadFile(configPath)
	if err != nil {
		log.Fatalf("读取配置文件失败: %v", err)
	}

	var cfg mqconfig
	err = yaml.Unmarshal(yamlFile, &cfg)
	if err != nil {
		log.Fatalf("解析配置文件失败: %v", err)
	}

	conn, err := amqp.Dial(fmt.Sprintf("amqp://%s:%s@%s:%s/%s", cfg.Mq.User, cfg.Mq.Password, cfg.Mq.Host, cfg.Mq.Port, cfg.Mq.Vhost))
	if err != nil {
		log.Fatalf("连接RabbitMQ失败: %v", err)
	}

	channel, err := conn.Channel()
	if err != nil {
		log.Fatalf("创建通道失败: %v", err)
	}

	return &OrderMQ{conn: conn, channel: channel}
}

func NewOrderQueue(orderMQ *OrderMQ) error {

	//创建交换机
	err := orderMQ.channel.ExchangeDeclare("order.exchange", "direct", true, false, false, false, nil)
	if err != nil {
		return fmt.Errorf("创建交换机失败: %v", err)
	}
	//创建队列
	_, err = orderMQ.channel.QueueDeclare("order.stock_reserved", true, false, false, false, nil)
	if err != nil {
		return fmt.Errorf("创建队列order.stock_reserved失败: %v", err)
	}
	_, err = orderMQ.channel.QueueDeclare("order.stock_failed", true, false, false, false, nil)
	if err != nil {
		return fmt.Errorf("创建队列order.stock_failed失败: %v", err)
	}
	//绑定队列到交换机
	err = orderMQ.channel.QueueBind("order.stock_reserved", "stock.reserved", "order.exchange", false, nil)
	if err != nil {
		return fmt.Errorf("绑定队列order.stock_reserved到交换机失败: %v", err)
	}
	err = orderMQ.channel.QueueBind("order.stock_failed", "stock.failed", "order.exchange", false, nil)
	if err != nil {
		return fmt.Errorf("绑定队列order.stock_failed到交换机失败: %v", err)
	}
	return nil
}

func (mq *OrderMQ) Publish(routingKey string, message []byte) error {
	//发送消息没有消费者接收，则重试3次
	for i := 0; i < 3; i++ {
		err := mq.channel.Publish("order.exchange", routingKey, true, false, amqp.Publishing{
			DeliveryMode: amqp.Persistent,
			ContentType:  "application/json",
			Body:         message,
			Headers:      amqp.Table{"x-retries": 0},
		})
		if err == nil {
			return nil
		}
		log.Printf("发送消息失败，重试第%d次,错误信息: %v", i+1, err)
	}
	return fmt.Errorf("发送消息失败")
}

func (mq *OrderMQ) CreatePublish(message []byte) error {
	return mq.Publish("order.created", message)
}

func (mq *OrderMQ) CancelRollbackPublish(message []byte) error {
	return mq.Publish("order.canceled", message)
}

func (mq *OrderMQ) FailedRollbackPublish(message []byte) error {
	return mq.Publish("order.failed", message)
}

func (mq *OrderMQ) Consume(queue string, orderRepository *repository.OrderRepository) error {
	msgs, err := mq.channel.Consume(queue, "", false, false, false, false, nil)
	if err != nil {
		return fmt.Errorf("消费消息失败: %v", err)
	}
	go func() {
		for msg := range msgs {
			err := handleStockMessage(msg.Body, orderRepository)
			if err != nil {
				log.Printf("队列%s处理消息失败: %v", queue, err)
				msg.Nack(false, false)
			} else {
				msg.Ack(false)
			}
		}
	}()
	return nil
}

func handleStockMessage(message []byte, orderRepository *repository.OrderRepository) error {
	var stockMessage StockMessage
	err := json.Unmarshal(message, &stockMessage)
	if err != nil {
		log.Printf("解析库存预留返回消息失败: %v", err)
		return fmt.Errorf("解析库存预留返回消息失败: %v", err)
	}

	log.Printf("stockMessage: %v", stockMessage)
	if stockMessage.ReserveResp {
		log.Printf("库存预留成功,订单ID: %d,等待支付", stockMessage.OrderID)
		err := orderRepository.UpdateOrderStatus(stockMessage.OrderID, "reserved")
		if err != nil {
			log.Printf("更新订单状态失败: %v", err)
			return fmt.Errorf("更新订单状态失败: %v", err)
		}
		return nil
	}

	log.Printf("库存预留失败,订单ID: %d", stockMessage.OrderID)
	err = orderRepository.UpdateOrderStatus(stockMessage.OrderID, "failed")
	if err != nil {
		log.Printf("更新订单状态失败: %v", err)
		return fmt.Errorf("更新订单状态失败: %v", err)
	}
	return fmt.Errorf("库存预留失败")
}

func (mq *OrderMQ) Close() error {
	if err := mq.channel.Close(); err != nil {
		return fmt.Errorf("关闭通道失败: %v", err)
	}
	if err := mq.conn.Close(); err != nil {
		return fmt.Errorf("关闭连接失败: %v", err)
	}
	return nil
}
